#include "Camera.h"
#include "InteractiveState.h"
#include "Input.h"

Camera::Camera() : 
m_nearClip(0.0f),
m_farClip(0.0f),
m_aspectRatio(0.0f),
m_fieldOfView(0.0f)
{}

void Camera::Prepare()
{
    Vec3 lookDir = (m_pos+m_dir);
    D3DXVECTOR3 vEyePos( m_pos.X(), m_pos.Y(), m_pos.Z());
    D3DXVECTOR3 vLookatPos( lookDir.X(), lookDir.Y(), lookDir.Z());
    D3DXVECTOR3 vUpVec( m_up.X(), m_up.Y(), m_up.Z());
    D3DXMatrixLookAtLH( &m_viewMatrix, &vEyePos, &vLookatPos, &vUpVec );
    m_frustum.SetViewInternals(m_pos, lookDir,m_up);
}

void Camera::SetProjection( float nearClip, float farClip, float ratio, float fieldOfView )
{
    m_nearClip = nearClip;
    m_farClip = farClip;
    m_aspectRatio = ratio;
    m_fieldOfView = fieldOfView;
    CreateProjectionMatrix();
}

void Camera::SetPosition( const Vec3& other )
{
    m_pos = other;
}

void Camera::SetDirection( const Vec3& other )
{
    m_dir = other;
}

void Camera::SetUpVector( const Vec3& other )
{
    m_up = other;
}

void Camera::CreateProjectionMatrix()
{
    //Create a perspective projection matrix ( RH is right handed )
    D3DXMatrixPerspectiveFovLH(&m_projectionMatrix, m_fieldOfView, m_aspectRatio, m_nearClip,m_farClip);
    m_frustum.SetProjectionInternalsPerspective(m_fieldOfView,m_aspectRatio,m_nearClip,m_farClip);
}

void Camera::Reset()
{
    m_dir = Vec3(0,0,1);
    m_pos = Vec3(0,0,0);
}

float Camera::GetNear()
{
    return m_nearClip;
}

float Camera::GetFar()
{
    return m_farClip;
}

void Camera::Update()
{
    //cam controls...

    //movement

    //forward
    if( Input::Instance()->GetKeyboard().GetKey(DIK_W) == Input::KeyState_Held)
    {
        m_pos += m_dir*0.9f;
    }
    //back
    if( Input::Instance()->GetKeyboard().GetKey(DIK_S) == Input::KeyState_Held)
    {
        m_pos -= m_dir*0.9f;
    }
    //left
    if( Input::Instance()->GetKeyboard().GetKey(DIK_A) == Input::KeyState_Held)
    {
        Vec3 left = m_dir.CrossProduct(m_up);
        left.normalise();
        m_pos += left * 0.3f;
    }
    //right
    if( Input::Instance()->GetKeyboard().GetKey(DIK_D) == Input::KeyState_Held)
    {
        Vec3 left = m_dir.CrossProduct(m_up);
        left.normalise();
        left.invert();
        m_pos += left * 0.1f;
    }
    //direct up
    if(Input::Instance()->GetKeyboard().GetKey(DIK_LSHIFT) == Input::KeyState_Held &&
        Input::Instance()->GetKeyboard().GetKey(DIK_W) == Input::KeyState_Held)
    {
        m_pos += m_up;
    }
    //direct down
    if(Input::Instance()->GetKeyboard().GetKey(DIK_LSHIFT) == Input::KeyState_Held &&
        Input::Instance()->GetKeyboard().GetKey(DIK_S) == Input::KeyState_Held)
    {
        m_pos += m_up.GetInverted() * 0.5f;
    }
    //direction
    if(Input::Instance()->GetKeyboard().GetKey(DIK_LEFT) == Input::KeyState_Held)
    {
        Vec3 left = m_dir.CrossProduct(m_up);
        left.normalise();        
        m_dir = Vector::lerp(m_dir, left, 0.01f);
        m_dir.normalise();
    }
    if(Input::Instance()->GetKeyboard().GetKey(DIK_RIGHT) == Input::KeyState_Held)
    {
        Vec3 left = m_dir.CrossProduct(m_up);
        left.normalise();
        left.invert();
        m_dir = Vector::lerp(m_dir, left, 0.01f);
        m_dir.normalise();
    }
    if(Input::Instance()->GetKeyboard().GetKey(DIK_UP) == Input::KeyState_Held)
    {
        m_dir = Vector::lerp(m_dir, m_up, 0.005f);
        m_dir.normalise();
    }
    if(Input::Instance()->GetKeyboard().GetKey(DIK_DOWN) == Input::KeyState_Held)
    {
        m_dir = Vector::lerp(m_dir, m_up.GetInverted(), 0.005f);
        m_dir.normalise();
    }
}
